package com.minidb.engine;

import com.minidb.storage.FileManager;
import com.minidb.utils.Condition;
import com.minidb.utils.Helpers;
import com.minidb.utils.Constants;

import java.util.*;

/**
 * CatalogManager（基于系统表 __catalog 装载/更新）
 * - 内存里维护：表 -> 列名列表、列类型列表
 * - 启动时：从 __catalog 扫描加载
 * - 创建表：更新内存，同时向 __catalog 追加记录，并创建表的数据目录
 */
public class CatalogManager {

    private final Map<String, List<String>> tableColumns = new HashMap<>();
    private final Map<String, List<String>> tableColumnTypes = new HashMap<>();
    
    // 新增：元数据缓存时间戳
    private final Map<String, Long> tableMetadataTimestamps = new HashMap<>();
    private long lastSystemTableScan = 0;
    
    private final FileManager fileManager;
    private final SystemCatalog sysCatalog;

    public CatalogManager(FileManager fm, SystemCatalog sysCatalog) {
        this.fileManager = fm;
        this.sysCatalog = sysCatalog;
    }

    // 增强的表存在性检查 - 支持缓存和性能优化
    public boolean tableExists(String table) {
        if (table == null || table.trim().isEmpty()) {
            return false;
        }
        
        // 检查内存缓存
        if (tableColumns.containsKey(table)) {
            return true;
        }
        
        // 如果缓存较旧，重新加载
        long currentTime = System.currentTimeMillis();
        if (currentTime - lastSystemTableScan > 30000) { // 30秒缓存过期
            loadFromSystemTable();
        }
        
        return tableColumns.containsKey(table);
    }

    /**
     * 创建表：
     * 1) 内存注册
     * 2) 创建数据目录
     * 3) 向 __catalog 追加每列元数据
     */
    public boolean createTable(String table, List<String> cols, List<String> types) {
        if (table == null || table.trim().isEmpty()) {
            throw new IllegalArgumentException("表名不能为空");
        }
        
        if (cols == null || cols.isEmpty()) {
            throw new IllegalArgumentException("列定义不能为空");
        }
        
        if (types == null || types.size() != cols.size()) {
            throw new IllegalArgumentException("列类型数量必须与列名数量匹配");
        }
        
        // 检查列名重复
        Set<String> columnSet = new HashSet<>(cols);
        if (columnSet.size() != cols.size()) {
            throw new IllegalArgumentException("列名不能重复");
        }
        
        if (tableColumns.containsKey(table)) {
            return false;
        }
        
        if (Constants.SYSTEM_CATALOG_TABLE.equalsIgnoreCase(table)) {
            throw new IllegalArgumentException("禁止以用户身份创建系统表 " + Constants.SYSTEM_CATALOG_TABLE);
        }

        try {
            // 1. 创建数据目录
            if (!fileManager.createTableFile(table)) {
                throw new RuntimeException("创建表文件失败");
            }
            
            // 2. 持久化元数据
            sysCatalog.initIfAbsent();
            if (!sysCatalog.appendEntriesTransactional(table, new ArrayList<>(cols), new ArrayList<>(types))) {
                // 回滚：删除已创建的文件
                fileManager.deleteTableFile(table);
                throw new RuntimeException("元数据持久化失败");
            }
            
            // 3. 更新内存缓存
            tableColumns.put(table, new ArrayList<>(cols));
            tableColumnTypes.put(table, new ArrayList<>(types));
            tableMetadataTimestamps.put(table, System.currentTimeMillis());
            
            return true;
            
        } catch (Exception e) {
            // 清理内存状态
            tableColumns.remove(table);
            tableColumnTypes.remove(table);
            tableMetadataTimestamps.remove(table);
            
            throw new RuntimeException("创建表失败: " + e.getMessage(), e);
        }
    }

    /** 增强的系统表加载方法 - 支持增量更新和错误恢复 */
    public void loadFromSystemTable() {
        try {
            // 备份当前状态
            Map<String, List<String>> backupColumns = new HashMap<>(tableColumns);
            Map<String, List<String>> backupTypes = new HashMap<>(tableColumnTypes);
            
            tableColumns.clear();
            tableColumnTypes.clear();
            tableMetadataTimestamps.clear();

            sysCatalog.initIfAbsent();
            List<List<String>> rows = sysCatalog.scanAll();
            
            long currentTime = System.currentTimeMillis();
            
            for (var r : rows) {
                if (r.size() < 4) {
                    System.err.println("警告：跳过不完整的元数据记录: " + r);
                    continue;
                }
                
                String table = r.get(0);
                String column = r.get(1);
                String type = r.get(2);
                
                // 跳过系统记录和删除标记
                if ("__SYSTEM__".equals(table) || "__DELETED__".equals(table)) {
                    continue;
                }
                
                // 验证数据有效性
                if (table.trim().isEmpty() || column.trim().isEmpty() || type.trim().isEmpty()) {
                    System.err.println("警告：跳过无效的元数据记录: " + r);
                    continue;
                }
                
                tableColumns.computeIfAbsent(table, k -> new ArrayList<>()).add(column);
                tableColumnTypes.computeIfAbsent(table, k -> new ArrayList<>()).add(type);
                tableMetadataTimestamps.put(table, currentTime);
            }
            
            lastSystemTableScan = currentTime;
            
            // 验证加载结果
            validateLoadedMetadata();
            
        } catch (Exception e) {
            System.err.println("元数据加载失败，尝试恢复: " + e.getMessage());
            
            // 尝试恢复机制
            attemptMetadataRecovery();
        }
    }
    
    /** 新增：验证加载的元数据 */
    private void validateLoadedMetadata() {
        for (Map.Entry<String, List<String>> entry : tableColumns.entrySet()) {
            String tableName = entry.getKey();
            List<String> columns = entry.getValue();
            List<String> types = tableColumnTypes.get(tableName);
            
            if (columns == null || columns.isEmpty()) {
                throw new IllegalStateException("表 " + tableName + " 缺少列定义");
            }
            
            if (types == null || types.size() != columns.size()) {
                throw new IllegalStateException("表 " + tableName + " 的列类型定义不完整");
            }
        }
    }
    
    /** 新增：元数据恢复机制 */
    private void attemptMetadataRecovery() {
        System.out.println("尝试元数据恢复...");
        
        try {
            // 扫描数据目录，重建基本的表结构信息
            // 这是一个简化的恢复机制
            
            // 清空当前状态
            tableColumns.clear();
            tableColumnTypes.clear();
            
            // 重新初始化系统表
            sysCatalog.initIfAbsent();
            
            System.out.println("元数据恢复完成，但可能丢失部分信息");
            
        } catch (Exception recoveryException) {
            throw new RuntimeException("元数据恢复失败: " + recoveryException.getMessage(), recoveryException);
        }
    }

    public List<String> getColumns(String table) { 
        return tableColumns.get(table); 
    }

    public List<String> getColumnTypes(String table) { 
        return tableColumnTypes.get(table); 
    }

    public String getColumnType(String table, String col) {
        List<String> cols = tableColumns.get(table);
        List<String> types = tableColumnTypes.get(table);
        if (cols == null) return null;
        int idx = cols.indexOf(col);
        return idx < 0 ? null : types.get(idx);
    }

    // —— WHERE 条件评估（沿用你原来的逻辑） —— //
    public boolean evaluateCondition(String table, Condition cond, List<String> record) {
        if (cond == null) return true;
        List<String> cols = tableColumns.get(table);
        List<String> types = tableColumnTypes.get(table);
        int idx = cols.indexOf(cond.columnName);
        if (idx < 0) throw new IllegalArgumentException("列不存在: " + cond.columnName);
        String colType = types.get(idx);
        String rv = record.get(idx), cv = cond.value, op = cond.operator;
        boolean isInt = colType.toUpperCase().contains("INT");
        if (isInt) {
            if (!Helpers.isNumeric(rv) || !Helpers.isNumeric(cv)) return false;
            long a = Long.parseLong(rv), b = Long.parseLong(cv);
            return switch (op) {
                case "=" -> a == b; case "!=", "<>" -> a != b; case "<" -> a < b;
                case "<=" -> a <= b; case ">" -> a > b; case ">=" -> a >= b; default -> false;
            };
        } else {
            int cmp = rv.compareTo(cv);
            return switch (op) {
                case "=" -> rv.equals(cv); case "!=", "<>" -> !rv.equals(cv);
                case "<" -> cmp < 0; case "<=" -> cmp <= 0; case ">" -> cmp > 0; case ">=" -> cmp >= 0; default -> false;
            };
        }
    }
}
